package rabbitmq

import (
    "github.com/streadway/amqp"

    "git.inspur.com/x/common/loggerfactory"
)

var logger = loggerfactory.GetLogger()

type MqClient struct {
    *amqp.Channel
}

// Connection amqp.Connection wrapper
type MqConnection struct {
    *amqp.Connection
}

// Channel amqp.Channel wapper
type MqChannel struct {
    *amqp.Channel
    closed int32
}

const delay = 5 // reconnect after delay seconds

//InitClient init amqp client
func InitClient(url string) (MqClient, error) {
    conn, err := amqp.Dial(url)
    if err != nil {
        _ = logger.Error("create mq connection error: ", err)
        return MqClient{}, err
    }

    channel, err := conn.Channel()
    if err != nil {
        _ = logger.Error("create mq channel error: ", err)
        return MqClient{}, err
    }

    logger.Info("init mq channel: ", channel)
    return MqClient{channel}, nil
}

//CloseClient close mq client
func (mq MqClient) CloseClient() {
    logger.Info("close mq channel")
    _ = mq.Close()
}

//Receive receive mq data
func (mq MqClient) Receive(exchange, queue, routingKey string, reader func(msg amqp.Delivery)) error {
    err := mq.ExchangeDeclare(
        exchange,
        "topic",
        true,
        false,
        false,
        false,
        nil,
    )
    if err != nil {
        _ = logger.Error("exchange declare error: ", err)
        return err
    }

    //args := make(amqp.Table)
    //args["x-dead-letter-exchange"] = model.Base.BssMqInfo.DeadLetterExchange
    //args["x-dead-letter-routing-key"] = model.Base.BssMqInfo.DeadLetterRouteKey
    //args["x-message-ttl"] = 300000

    _, err = mq.QueueDeclare(
        queue, // name
        true,  // durable
        false, // delete when unused
        false, // exclusive
        false, // no-wait
        nil,   // arguments
    )
    if err != nil {
        _ = logger.Error("queue declare error: ", err)
        return err
    }

    err = mq.QueueBind(
        queue,
        routingKey,
        exchange,
        false,
        nil,
    )
    if err != nil {
        _ = logger.Error("queue bind error: ", err)
        return err
    }

    messages, err := mq.Consume(
        queue, // queue
        "",    // consumer
        true,  // auto-ack
        false, // exclusive
        false, // no-local
        false, // no-wait
        nil,   // args
    )
    if err != nil {
        _ = logger.Error("receive message error: ", err)
        return err
    }

    go func() {
        for m := range messages {
            reader(m)
        }
    }()
    return nil
}

//Send send data to mq
func (mq MqClient) Send(exchange, queue, routingKey, contentType string, message []byte, args amqp.Table) error {
    err := mq.ExchangeDeclare(
        exchange,
        "topic",
        true,
        false,
        false,
        false,
        nil,
    )
    if err != nil {
        _ = logger.Error("exchange declare error: ", err)
        return err
    }

    //args := make(amqp.Table)
    //args["x-dead-letter-exchange"] = model.Base.BssMqInfo.DeadLetterExchange
    //args["x-dead-letter-routing-key"] = model.Base.BssMqInfo.DeadLetterRouteKey
    //args["x-message-ttl"] = 300000
    _, err = mq.QueueDeclare(
        queue, // name
        true,  // durable
        false, // delete when unused
        false, // exclusive
        false, // no-wait
        args,  // arguments
    )
    if err != nil {
        _ = logger.Error("queue declare error: ", err)
        return err
    }

    err = mq.QueueBind(
        queue,
        routingKey,
        exchange,
        false,
        nil,
    )
    if err != nil {
        _ = logger.Error("queue bind error: ", err)
        return err
    }

    err = mq.Publish(
        exchange,   // exchange
        routingKey, // routing key
        false,      // mandatory
        false,      // immediate
        amqp.Publishing{
            ContentType: contentType,
            Body:        message,
            // Headers:     headers,
        })
    if err != nil {
        _ = logger.Error("publish message error: ", err)
        return err
    }
    return nil
}
